using System;
using System.Data;
using System.Xml;

using OR.Reuse.Persistence;

using OR.Lazarus.Config;

using Notation		= OR.Lazarus.Business.Entities.Notation;

namespace OR.Lazarus.Library.DataTier.Source
{
	public class FieldDetail : OR.Lazarus.Library.DataTier.Source.Lazarus.FieldDetail
	{
		public bool IsForeignKey
		{
			get
			{
				return ( this.GetIsForeignKey() );
			}
		}

		public bool IsPrimaryKey
		{
			get
			{
				return ( this.GetIsPrimaryKey() );
			}
		}

		public bool IsClustered
		{
			get
			{
				return ( this.GetIsClustered() );
			}
		}

		/// <summary>
		/// Read-only property.  Returns whether or not the current field is a foreign key (reference) to another row, which may or may not reside in another table.
		/// </summary>
		/// <returns></returns>
		public virtual bool GetIsForeignKey()
		{
			bool			vReturn = false;

			IndexDetail	vIndex = this.GetForeignKey();

			vReturn = ( vIndex != null );

			return ( vReturn );
		}

		public virtual IndexDetail GetForeignKey()
		{
			IndexDetail vReturn = null;

			foreach ( IndexDetail vIndex in this.Indexes )
			{
				if ( vIndex.Type == CompilerSettings.INDEXTYPE_FOREIGN )
				{
					vReturn = vIndex;

					break;
				}
			}

			return ( vReturn );
		}

		public virtual bool GetIsPrimaryKey()
		{
			bool v_bReturn = false;

			foreach ( IndexDetail v_oIndex in this.Indexes )
			{
				if ( v_oIndex.Type == CompilerSettings.INDEXTYPE_PRIMARY )
				{
					v_bReturn = true;

					break;
				}
			}

			return ( v_bReturn );
		}

		public virtual bool GetIsClustered()
		{
			bool v_bReturn = false;

			foreach ( IndexDetail v_oIndex in this.Indexes )
			{
				if ( v_oIndex.Type == CompilerSettings.INDEXTYPE_CLUSTERED )
				{
					v_bReturn = true;

					break;
				}
			}

			return ( v_bReturn );
		}	

		public void Initialize( Notation.NotationDetail pNotation )
		{
			this.OnInitalize( pNotation );

			foreach ( ConstraintDetail vConstraint in this.Constraints )
			{
				vConstraint.Initialize();
			}
		}

		protected virtual void OnInitalize( Notation.NotationDetail pNotation )
		{
			this.OnInitializeType();

			this.OnInitializeName();

			this.OnInitializeRequired();

			this.OnApplyNotation( pNotation );
		}

		protected virtual void OnInitializeRequired()
		{
			if ( this.IsPrimaryKey )
			{
				this.Required = true;
			}
		}

		protected virtual void OnApplyNotation( Notation.NotationDetail pNotation )
		{
			Notation.MapDetail	vNotation = pNotation.Maps[ this.DataType ];

			if ( vNotation != null )
			{
				this.Name = vNotation.Target + this.Name;
			}
		}

		protected virtual void OnInitializeName()
		{
			string	v_szObjectName	= String.Empty;

			if ( this.ParentEntity != null )
			{
				if ( this.ParentEntity is ObjectDetail )
				{
					v_szObjectName = ( ( ObjectDetail )this.ParentEntity ).Name;
				}
				else if ( this.ParentEntity is IntersectionDetail )
				{
					v_szObjectName = ( ( IntersectionDetail )this.ParentEntity ).Name;
				}
				else
				{
					throw new ApplicationException( String.Format( "InitializeName failed for field [{0}].  The Parent parameter must be an ObjectDetail or IntersectionDetail.", this.Name ) );
				}
			}

			if ( String.IsNullOrEmpty( this.Alias ) )
			{
				this.Alias = this.Name.ToLower();
			}

			if ( String.IsNullOrEmpty( this.LogicalName ) )
			{
				this.LogicalName = this.Name;
			}

			if ( String.IsNullOrEmpty( this.FriendlyName ) )
			{
				this.FriendlyName = this.Name;
			}

			foreach ( IndexDetail vIndex in this.Indexes )
			{
				if ( vIndex.Type == CompilerSettings.INDEXTYPE_FOREIGN )
				{
					if ( String.IsNullOrEmpty( vIndex.Accessor ) )
					{
						vIndex.Accessor = this.Name;
					}

					if ( String.IsNullOrEmpty( vIndex.Alias ) )
					{
						vIndex.Alias = vIndex.Accessor.ToLower();
					}
				}

				if ( String.IsNullOrEmpty( vIndex.Name ) )
				{
					switch ( vIndex.Type )
					{
						case CompilerSettings.INDEXTYPE_FOREIGN:
						{
							vIndex.Name = CompilerSettings.NOTATION_INDEX + v_szObjectName + "_" + this.Name;

							break;
						}
						case CompilerSettings.INDEXTYPE_PRIMARY:
						{
							vIndex.Name	= CompilerSettings.NOTATION_PRIMARYKEY + v_szObjectName;

							break;
						}
						default:
						{
							vIndex.Name = CompilerSettings.NOTATION_INDEX + v_szObjectName + "_" + this.Name;

							break;
						}
					}
				}
				else
				{
					if ( vIndex.Type == CompilerSettings.INDEXTYPE_FOREIGN )
					{
						vIndex.Name = CompilerSettings.NOTATION_INDEX + vIndex.Name;
					}
				}

				if ( String.IsNullOrEmpty( vIndex.ConstraintName ) )
				{
					switch ( vIndex.Type )
					{
						case CompilerSettings.INDEXTYPE_FOREIGN:
						{
							vIndex.ConstraintName = CompilerSettings.NOTATION_FOREIGNKEY + v_szObjectName + "_" + this.Name;

							break;
						}
						case CompilerSettings.INDEXTYPE_PRIMARY:
						{
							vIndex.ConstraintName = CompilerSettings.NOTATION_PRIMARYKEY + v_szObjectName + "_" + this.Name;

							break;
						}
					}
				}
			}
		}

		protected virtual void OnInitializeType()
		{
			if ( !String.IsNullOrEmpty( this.DataType ) )
			{
            switch ( this.DataType )
            {
               case CompilerSettings.DATATYPE_BOOLEAN:
               case CompilerSettings.DATATYPE_DATETIME:
               case CompilerSettings.DATATYPE_DECIMAL:
               case CompilerSettings.DATATYPE_FLOAT:
               case CompilerSettings.DATATYPE_GUID:
               case CompilerSettings.DATATYPE_IDENTITY:
               case CompilerSettings.DATATYPE_INT:
               case CompilerSettings.DATATYPE_SMALLINT:
               case CompilerSettings.DATATYPE_BIGINT:
               case CompilerSettings.DATATYPE_TINYINT:
               case CompilerSettings.DATATYPE_MONEY:
               case CompilerSettings.DATATYPE_VARCHAR:
               case CompilerSettings.DATATYPE_TEXT:
                  {
                     break;
                  }
               default:
                  {
                     string ErrorInvalidType = "Initialization of field {0}.{1} failed: Data Type '{2}' is invalid.";

                     throw new ApplicationException( String.Format( ErrorInvalidType, ( ( ObjectDetail )this.ParentEntity ).Name, this.Name, this.DataType ) );
                  }
            }

				if ( this.DataType == CompilerSettings.DATATYPE_IDENTITY )
				{
					this.AutoGenerate = true;
				}
			}

		}
	}
}
   